import 'package:flutter/material.dart';

/// 方向定义：四边 + 四个角
enum ResizeDirection {
  left,
  right,
  top,
  bottom,
  topLeft,
  topRight,
  bottomLeft,
  bottomRight,
}

/// 拖拽更新数据
class ResizeUpdate {
  final ResizeDirection direction;
  final double? width;
  final double? height;
  final Offset delta; // 本次累计位移 (相对拖拽起点)

  const ResizeUpdate({
    required this.direction,
    required this.delta,
    this.width,
    this.height,
  });
}

typedef ResizeCallback = void Function(ResizeUpdate update);

/// 可调整大小的面板：不直接持有尺寸状态，而是通过回调把新尺寸交给外部控制
/// - 通过 [handles] 指定启用哪些方向/角的拖拽
/// - 提供最小/最大宽高约束
/// - 提供开始/进行/结束回调，便于外部同步状态
class ResizablePanel extends StatefulWidget {
  final Widget child;

  /// 当前宽/高（由外部控制并传入）。
  /// 如果为 null，则对应方向不启用尺寸计算（仅触发回调，width/height 为 null）。
  final double? width;
  final double? height;

  /// 约束
  final double? minWidth;
  final double? maxWidth;
  final double? minHeight;
  final double? maxHeight;

  /// 启用的拖拽方向/角
  final Set<ResizeDirection> handles;

  /// 拖拽手柄的可点击厚度（像素）
  final double handleThickness;

  /// 回调
  final ResizeCallback? onResizeStart;
  final ResizeCallback? onResizing;
  final ResizeCallback? onResizeEnd;

  const ResizablePanel({
    super.key,
    required this.child,
    this.width,
    this.height,
    this.minWidth,
    this.maxWidth,
    this.minHeight,
    this.maxHeight,
    this.handles = const {ResizeDirection.right},
    this.handleThickness = 6.0,
    this.onResizeStart,
    this.onResizing,
    this.onResizeEnd,
  });

  @override
  State<ResizablePanel> createState() => _ResizablePanelState();
}

class _ResizablePanelState extends State<ResizablePanel> {
  double _startWidth = 0;
  double _startHeight = 0;
  double _dxTotal = 0;
  double _dyTotal = 0;

  void _onPanStart(ResizeDirection dir, DragStartDetails details) {
    _dxTotal = 0;
    _dyTotal = 0;
    _startWidth = widget.width ?? 0;
    _startHeight = widget.height ?? 0;

    widget.onResizeStart?.call(ResizeUpdate(
      direction: dir,
      delta: Offset.zero,
      width: widget.width,
      height: widget.height,
    ));
  }

  void _onPanUpdate(ResizeDirection dir, DragUpdateDetails details) {
    _dxTotal += details.delta.dx;
    _dyTotal += details.delta.dy;

    final computed = _computeNewSize(dir, _dxTotal, _dyTotal);

    widget.onResizing?.call(ResizeUpdate(
      direction: dir,
      delta: Offset(_dxTotal, _dyTotal),
      width: computed.$1,
      height: computed.$2,
    ));
  }

  void _onPanEnd(ResizeDirection dir, DragEndDetails details) {
    final computed = _computeNewSize(dir, _dxTotal, _dyTotal);
    widget.onResizeEnd?.call(ResizeUpdate(
      direction: dir,
      delta: Offset(_dxTotal, _dyTotal),
      width: computed.$1,
      height: computed.$2,
    ));
  }

  /// 返回 (newWidth, newHeight)
  (double?, double?) _computeNewSize(ResizeDirection dir, double dx, double dy) {
    double? newWidth = widget.width;
    double? newHeight = widget.height;

    bool horizontalLeft = dir == ResizeDirection.left || dir == ResizeDirection.topLeft || dir == ResizeDirection.bottomLeft;
    bool horizontalRight = dir == ResizeDirection.right || dir == ResizeDirection.topRight || dir == ResizeDirection.bottomRight;
    bool verticalTop = dir == ResizeDirection.top || dir == ResizeDirection.topLeft || dir == ResizeDirection.topRight;
    bool verticalBottom = dir == ResizeDirection.bottom || dir == ResizeDirection.bottomLeft || dir == ResizeDirection.bottomRight;

    if (newWidth != null) {
      if (horizontalRight) {
        newWidth = _startWidth + dx;
      } else if (horizontalLeft) {
        newWidth = _startWidth - dx;
      }
      if (newWidth != null) {
        final minW = widget.minWidth ?? 0;
        final maxW = widget.maxWidth ?? double.infinity;
        newWidth = newWidth.clamp(minW, maxW);
      }
    }

    if (newHeight != null) {
      if (verticalBottom) {
        newHeight = _startHeight + dy;
      } else if (verticalTop) {
        newHeight = _startHeight - dy;
      }
      if (newHeight != null) {
        final minH = widget.minHeight ?? 0;
        final maxH = widget.maxHeight ?? double.infinity;
        newHeight = newHeight.clamp(minH, maxH);
      }
    }

    return (newWidth, newHeight);
  }

  @override
  Widget build(BuildContext context) {
    // 使用 Stack 叠加手柄
    return Stack(
      children: [
        // 内容区域（按需施加宽/高）
        SizedBox(
          width: widget.width,
          height: widget.height,
          child: widget.child,
        ),
        // 句柄层覆盖在内容之上（按父尺寸填充）
        Positioned.fill(child: Stack(children: _buildHandles())),
      ],
    );
  }

  List<Widget> _buildHandles() {
    final t = widget.handleThickness;
    final children = <Widget>[];

    bool has(ResizeDirection d) => widget.handles.contains(d);

    // 边
    if (has(ResizeDirection.left)) {
      children.add(_edgeHandle(
        alignment: Alignment.centerLeft,
        size: Size(t, double.infinity),
        cursor: SystemMouseCursors.resizeLeftRight,
        direction: ResizeDirection.left,
      ));
    }
    if (has(ResizeDirection.right)) {
      children.add(_edgeHandle(
        alignment: Alignment.centerRight,
        size: Size(t, double.infinity),
        cursor: SystemMouseCursors.resizeLeftRight,
        direction: ResizeDirection.right,
      ));
    }
    if (has(ResizeDirection.top)) {
      children.add(_edgeHandle(
        alignment: Alignment.topCenter,
        size: Size(double.infinity, t),
        cursor: SystemMouseCursors.resizeUpDown,
        direction: ResizeDirection.top,
      ));
    }
    if (has(ResizeDirection.bottom)) {
      children.add(_edgeHandle(
        alignment: Alignment.bottomCenter,
        size: Size(double.infinity, t),
        cursor: SystemMouseCursors.resizeUpDown,
        direction: ResizeDirection.bottom,
      ));
    }

    // 角
    if (has(ResizeDirection.topLeft)) {
      children.add(_cornerHandle(
        alignment: Alignment.topLeft,
        size: Size(t, t),
        cursor: SystemMouseCursors.resizeUpLeftDownRight,
        direction: ResizeDirection.topLeft,
      ));
    }
    if (has(ResizeDirection.topRight)) {
      children.add(_cornerHandle(
        alignment: Alignment.topRight,
        size: Size(t, t),
        cursor: SystemMouseCursors.resizeUpRightDownLeft,
        direction: ResizeDirection.topRight,
      ));
    }
    if (has(ResizeDirection.bottomLeft)) {
      children.add(_cornerHandle(
        alignment: Alignment.bottomLeft,
        size: Size(t, t),
        cursor: SystemMouseCursors.resizeUpRightDownLeft,
        direction: ResizeDirection.bottomLeft,
      ));
    }
    if (has(ResizeDirection.bottomRight)) {
      children.add(_cornerHandle(
        alignment: Alignment.bottomRight,
        size: Size(t, t),
        cursor: SystemMouseCursors.resizeUpLeftDownRight,
        direction: ResizeDirection.bottomRight,
      ));
    }

    return children;
  }

  Widget _edgeHandle({
    required Alignment alignment,
    required Size size,
    required MouseCursor cursor,
    required ResizeDirection direction,
  }) {
    return Align(
      alignment: alignment,
      child: MouseRegion(
        cursor: cursor,
        child: GestureDetector(
          behavior: HitTestBehavior.translucent,
          onPanStart: (d) => _onPanStart(direction, d),
          onPanUpdate: (d) => _onPanUpdate(direction, d),
          onPanEnd: (d) => _onPanEnd(direction, d),
          child: SizedBox(width: size.width, height: size.height),
        ),
      ),
    );
  }

  Widget _cornerHandle({
    required Alignment alignment,
    required Size size,
    required MouseCursor cursor,
    required ResizeDirection direction,
  }) {
    return Align(
      alignment: alignment,
      child: MouseRegion(
        cursor: cursor,
        child: GestureDetector(
          behavior: HitTestBehavior.translucent,
          onPanStart: (d) => _onPanStart(direction, d),
          onPanUpdate: (d) => _onPanUpdate(direction, d),
          onPanEnd: (d) => _onPanEnd(direction, d),
          child: SizedBox(width: size.width, height: size.height),
        ),
      ),
    );
  }
}
